package com.um.jdy.app.device.manager;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.um.jdy.app.charge.manager.OrderManager;
import com.um.jdy.app.device.entity.dto.DeviceStationListQuery;
import com.um.jdy.app.device.entity.dto.StationHomeQuery;
import com.um.jdy.app.device.entity.dto.StationListQuery;
import com.um.jdy.app.device.entity.dto.StationQuery;
import com.um.jdy.app.device.entity.vo.*;
import com.um.jdy.common.activity.entity.vo.CouponsAndStationVO;
import com.um.jdy.common.activity.entity.vo.DiscountsAndStationVO;
import com.um.jdy.common.activity.enums.ActivityEnum;
import com.um.jdy.common.activity.service.CouponsStationService;
import com.um.jdy.common.activity.service.DiscountsStationService;
import com.um.jdy.common.device.code.DeviceCode;
import com.um.jdy.common.device.enums.DeviceEnum;
import com.um.jdy.common.device.service.StationService;
import com.um.jdy.common.member.entity.po.MemberUser;
import com.um.jdy.common.member.service.MemberUserService;
import com.um.jdy.common.shop.entity.po.Diy;
import com.um.jdy.common.shop.enums.DiyEnum;
import com.um.jdy.common.shop.service.DiyService;
import com.um.jdy.common.system.entity.po.Param;
import com.um.jdy.common.system.service.ParamService;
import com.um.jdy.rpc.enums.DeviceTypeEnum;
import com.um.springboot.starter.config.SystemSQL;
import com.um.springboot.starter.core.StringJsonRedisTemplate;
import com.um.springboot.starter.entity.Page;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.utils.JSONUtil;
import com.um.springboot.starter.utils.StringUtil;
import com.um.springboot.starter.utils.UMBeanUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @Title
 * @Description
 * @Author renjunwei
 * @Date 2023/5/22 10:37
 */
@Slf4j
@Service
public class StationManager {

    @Autowired
    StationService stationService;

    @Autowired
    ParamService paramService;

    @Autowired
    CouponsStationService couponsStationService;

    @Autowired
    DiscountsStationService discountsStationService;

    @Autowired
    StringJsonRedisTemplate redisTemplate;

    @Autowired
    DiyService diyService;

    @Autowired
    MemberUserService userService;

    @Autowired
    OrderManager orderManager;

    public Page<StationItemVO> getPage(StationListQuery query){
        Page<StationItemVO> page = new Page(query);

        StringBuffer conditionSql = new StringBuffer();
        List conditionParams = ListUtil.toList(query.getLongitude(), query.getLatitude());
        String device_type= query.getDeviceType();
        if(!StringUtil.isEmpty(device_type)) {
            Map deviceTypeMap = new HashMap();
            deviceTypeMap.put("EB", " and t.eb_total_num > 0");
            deviceTypeMap.put("EV", " and t.ev_total_num > 0");
            deviceTypeMap.put("EBox", " and t.ebox_total_num > 0");
            deviceTypeMap.put("PB", " and (t.pb_total_num > 0)");

            if(StationListQuery.Type.Available == query.getType()){
                deviceTypeMap.put("EB", " and t.eb_free_num > 0");
                deviceTypeMap.put("EV", " and t.ev_free_num > 0");
                deviceTypeMap.put("EBox", " and t.ebox_free_num > 0");
                deviceTypeMap.put("PB", " and (t.pb_rent_num > 0)");
            }

            if(deviceTypeMap.containsKey(device_type)) {
                conditionSql.append(StringUtil.getTrim(deviceTypeMap.get(device_type)));
            }

        }else{
            if(StationListQuery.Type.Available == query.getType()){
                conditionSql.append(" and (t.eb_free_num > 0 or t.pb_rent_num > 0 or t.ebox_free_num > 0 or t.ev_free_num > 0) ");
            }
        }


        if(StrUtil.isNotEmpty(query.getName())){
            conditionSql.append(" and s.name like ? ");
            conditionParams.add(StringUtil.getQueryParam(query.getName()));
        }


        conditionSql.append(" and s.com_id = ? ");
        conditionParams.add(stationService.getComId());

        String sql = SystemSQL.getInstance().getSystemSQL("get_station_page").replace("[condition]", conditionSql.toString());
        String sumSQL = SystemSQL.getInstance().getSystemSQL("get_station_count").replace("[condition]", conditionSql.toString());

        page = stationService.getViewModelPageBySql(page, sql, sumSQL, StationItemVO.class, conditionParams.toArray());

        List<CouponsAndStationVO> couponsList = couponsStationService.getAllCoupons(StpUtil.getLoginId(null));
        List<DiscountsAndStationVO> discountsList = discountsStationService.getAllDiscounts();

        page.getResult().forEach(item -> {
            item.setHasCoupons(couponsList.stream().anyMatch(coupons ->
                    ActivityEnum.UseRange.All.name().equals(coupons.getAvailable()) ||
                            coupons.getDeviceStationIdList().contains(item.getDeviceStationId())));
            item.setHasMoney(discountsList.stream().anyMatch(discounts ->
                    ActivityEnum.DiscountsType.Money.name().equals(discounts.getType()) &&
                            (ActivityEnum.UseRange.All.name().equals(discounts.getAvailableStation()) ||
                                    discounts.getDeviceStationIdList().contains(item.getDeviceStationId()))));
            item.setHasDiscount(discountsList.stream().anyMatch(discounts ->
                    ActivityEnum.DiscountsType.Discount.name().equals(discounts.getType()) &&
                            (ActivityEnum.UseRange.All.name().equals(discounts.getAvailableStation()) ||
                                    discounts.getDeviceStationIdList().contains(item.getDeviceStationId()))));
        });

        return page;
    }


    /**
     * 查询站场详情
     * @param query
     * @return
     */
    public StationDetailVO getDetail(StationQuery query){
        StationDetailVO detail = stationService.getViewModel("get_station_detail", StationDetailVO.class,
                new Object[]{query.getLongitude(), query.getLatitude(), query.getStationId()});

        if(detail == null){
            throw new ServiceException(DeviceCode.NoStation);
        }

        if(!StringUtil.isEmpty(detail.getLabelItems())){
            List<String> labelItems = JSONUtil.parseJSONToList(detail.getLabelItems());
            List<Param> params = paramService.getList("path","station.label_items","sort_no","asc");
            List<ParamItemVO> labelList = new ArrayList<>();
            for(String label : labelItems){
                for(Param param : params){
                    if(param.getPKey().equals(label)){
                        ParamItemVO paramItemVO = new ParamItemVO();
                        paramItemVO.setLabel(param.getPValue());
                        paramItemVO.setValue(param.getPKey());
                        labelList.add(paramItemVO);
                    }
                }
            }
            detail.setLabelList(labelList);
        }
        else
            detail.setLabelList(new ArrayList<>());

        if(!StringUtil.isEmpty(detail.getServiceItems())) {
            List<String> serviceItems = JSONUtil.parseJSONToList(detail.getServiceItems());
            List<Param> params = paramService.getList("path","station.service_items","sort_no","asc");
            List<ParamItemVO> serviceList = new ArrayList<>();
            for(String label : serviceItems){
                for(Param param : params){
                    if(param.getPKey().equals(label)){
                        ParamItemVO paramItemVO = new ParamItemVO();
                        paramItemVO.setLabel(param.getPValue());
                        paramItemVO.setValue(param.getPKey());
                        serviceList.add(paramItemVO);
                    }
                }
            }
            detail.setServiceList(serviceList);
        }
        else
            detail.setServiceList(new ArrayList<>());

        detail.setEvAcList(stationService.getViewModelList("get_station_ev_device_list", GunItemVO.class,new Object[]{query.getStationId(), DeviceEnum.AcAndDc.AC.name()}));
        detail.setEvDcList(stationService.getViewModelList("get_station_ev_device_list", GunItemVO.class,new Object[]{query.getStationId(), DeviceEnum.AcAndDc.DC.name()}));
        detail.setEbList(stationService.getViewModelList("get_station_device_list", DeviceItemVO.class,new Object[]{query.getStationId(), DeviceTypeEnum.EB.name()}));
        detail.setEboxList(stationService.getViewModelList("get_station_device_list", DeviceItemVO.class,new Object[]{query.getStationId(), DeviceTypeEnum.EBox.name()}));


        boolean isAcSameFee = detail.getEvAcList().stream()
                .map(GunItemVO::getDeviceFeeId) // 假设Item有一个getField方法
                .distinct()
                .count() == 1;

        boolean isDcSameFee = detail.getEvDcList().stream()
                .map(GunItemVO::getDeviceFeeId) // 假设Item有一个getField方法
                .distinct()
                .count() == 1;

        if(isAcSameFee && detail.getEvAcList().size() > 0){
            CurrentTimeFeeVO acCurrentTimeFee = UMBeanUtils.copyBean(detail.getEvAcList().get(0),CurrentTimeFeeVO.class);
            detail.setAcCurrentTimeFee(acCurrentTimeFee);
        }

        if(isDcSameFee && detail.getEvDcList().size() > 0){
            CurrentTimeFeeVO dcCurrentTimeFee = UMBeanUtils.copyBean(detail.getEvDcList().get(0),CurrentTimeFeeVO.class);
            detail.setDcCurrentTimeFee(dcCurrentTimeFee);
        }

        List<CouponsAndStationVO> couponsList = couponsStationService.getAllCoupons(StpUtil.getLoginId(null));
        List<DiscountsAndStationVO> discountsList = discountsStationService.getAllDiscounts();

        detail.setCoupons(couponsList.stream().filter(coupons ->
                        ActivityEnum.UseRange.All.name().equals(coupons.getAvailable()) ||
                                coupons.getDeviceStationIdList().contains(detail.getDeviceStationId()))
                .collect(Collectors.toList()));
        detail.setMoneys(discountsList.stream().filter(discounts ->
                        ActivityEnum.DiscountsType.Money.name().equals(discounts.getType()) &&
                                (ActivityEnum.UseRange.All.name().equals(discounts.getAvailableStation()) ||
                                        discounts.getDeviceStationIdList().contains(detail.getDeviceStationId())))
                .collect(Collectors.toList()));
        detail.setDiscounts(discountsList.stream().filter(discounts ->
                        ActivityEnum.DiscountsType.Discount.name().equals(discounts.getType()) &&
                                (ActivityEnum.UseRange.All.name().equals(discounts.getAvailableStation()) ||
                                        discounts.getDeviceStationIdList().contains(detail.getDeviceStationId())))
                .collect(Collectors.toList()));

        detail.setHasCoupons(detail.getCoupons().size() > 0);
        detail.setHasMoney(detail.getMoneys().size() > 0);
        detail.setHasDiscount(detail.getDiscounts().size() > 0);

        return detail;
    }


    public Page<DeviceStationItemVO> getDeviceStationPage(String deviceType, DeviceStationListQuery query){
        Page<DeviceStationItemVO> page = new Page(query);

        StringBuffer conditionSql = new StringBuffer();
        List conditionParams = ListUtil.toList(query.getLongitude(), query.getLatitude(),deviceType);

        Map deviceTypeMap = new HashMap();
        deviceTypeMap.put("EB", " and t.eb_total_num > 0");
        deviceTypeMap.put("EV", " and (t.ac_total_num > 0 or t.dc_total_num > 0)");
        deviceTypeMap.put("EBox", " and t.ebox_total_num > 0");
        deviceTypeMap.put("PB", " and  (t.pb_rent_num > 0 or t.pb_return_num > 0)");

        if(DeviceStationListQuery.Type.Available == query.getType()){
            deviceTypeMap.put("EB", " and t.eb_free_num > 0");
            deviceTypeMap.put("EV", " and (t.ac_free_num > 0 or t.dc_free_num > 0)");
            deviceTypeMap.put("EBox", " and t.ebox_free_num > 0");
            deviceTypeMap.put("PB", " and t.pb_rent_num > 0");
        }else if(DeviceStationListQuery.Type.Returnable == query.getType()){
            deviceTypeMap.put("PB", " and t.pb_return_num > 0");
        }

        if(deviceTypeMap.containsKey(deviceType)) {
            conditionSql.append(StringUtil.getTrim(deviceTypeMap.get(deviceType)));
        }


        if(StrUtil.isNotEmpty(query.getName())){
            conditionSql.append(" and s.name like ? ");
            conditionParams.add(StringUtil.getQueryParam(query.getName()));
        }


        conditionSql.append(" and s.com_id = ? ");
        conditionParams.add(stationService.getComId());

        String sql = SystemSQL.getInstance().getSystemSQL("get_device_station_page").replace("[condition]", conditionSql.toString());
        String sumSQL = SystemSQL.getInstance().getSystemSQL("get_device_station_count").replace("[condition]", conditionSql.toString());

        page = stationService.getViewModelPageBySql(page, sql, sumSQL, DeviceStationItemVO.class, conditionParams.toArray());

        List<CouponsAndStationVO> couponsList = couponsStationService.getAllCoupons(StpUtil.getLoginId(null));
        List<DiscountsAndStationVO> discountsList = discountsStationService.getAllDiscounts();

        page.getResult().forEach(item -> {
            item.setHasCoupons(couponsList.stream().anyMatch(coupons ->
                    ActivityEnum.UseRange.All.name().equals(coupons.getAvailable()) ||
                            coupons.getDeviceStationIdList().contains(item.getDeviceStationId())));
            item.setHasMoney(discountsList.stream().anyMatch(discounts ->
                    ActivityEnum.DiscountsType.Money.name().equals(discounts.getType()) &&
                            (ActivityEnum.UseRange.All.name().equals(discounts.getAvailableStation()) ||
                                    discounts.getDeviceStationIdList().contains(item.getDeviceStationId()))));
            item.setHasDiscount(discountsList.stream().anyMatch(discounts ->
                    ActivityEnum.DiscountsType.Discount.name().equals(discounts.getType()) &&
                            (ActivityEnum.UseRange.All.name().equals(discounts.getAvailableStation()) ||
                                    discounts.getDeviceStationIdList().contains(item.getDeviceStationId()))));
        });

        return page;
    }

    /**
     * 查询DIY首页
     * @return
     */
    public Map getStationHome(StationHomeQuery query) {
        String redisTemplateKey = DiyEnum.Type.Station.getValue() + "-" + stationService.getComId();
        Map pageData = redisTemplate.opsForHash().entries(redisTemplateKey);
        if(null == pageData || pageData.isEmpty()) {
            Diy diy = diyService.getEntity(new String[]{"type", "pro_name"}, new String[]{"diy", DiyEnum.Type.Station.getValue()});
            pageData = this.getDiyData(JSONUtil.parseJSONToMap(diy.getProValue()), query);
            redisTemplate.opsForHash().putAll(redisTemplateKey, pageData);
            redisTemplate.expireAt(redisTemplateKey, DateUtil.endOfHour(DateUtil.date()));
        }else {
            this.getDiyData(pageData, query);
        }
        return pageData;
    }


    private Map getDiyData(Map pageData, StationHomeQuery query) {
        List<Map> componentList = (List<Map>)pageData.get("items");

        int orders = 0;
        MemberUser user = userService.get();
        String uid = user.getMemberUserId();
        if(uid != null) {
            orders = orderManager.getChargingOrders().size();
        }

        for(Map component : componentList) {
            String componentName = StringUtil.getTrim(component.get("component_name"));
            switch (componentName) {
                case "StationBigBannerData":
                    break;
                case "StationShortcutsOneData":
                case "StationShortcutsTwoData":
                case "StationShortcutsThreeData":
                    List<Map> dataItems = (List<Map>)component.get("data_items");

                    for(Map dataItem : dataItems) {
                        String explain = StringUtil.getTrim(dataItem.get("explain"));
                        boolean hasOrders = explain.contains("{orders}");
                        if(hasOrders) {
                            dataItem.put("explain", explain.replace("{orders}", StringUtil.getTrim(orders)));
                        }
                    }

                    break;
                case "StationMapData":
                case "StationListData":

                    int size = 20;
                    if(componentName.equals("StationListData")) {
                        size = StringUtil.toInt(component.get("list_num"));
                    }


                    DeviceStationListQuery listQuery = new DeviceStationListQuery();
                    listQuery.setLatitude(query.getLatitude());
                    listQuery.setLongitude(query.getLongitude());
                    listQuery.setPage_no(1);
                    listQuery.setPage_size(size);

                    String device_type = StringUtil.getTrim(component.get("device_type"));

                    Page<DeviceStationItemVO> page = this.getDeviceStationPage(device_type, listQuery);


                    component.put("data_items", page.getResult());

//                    StationListQuery listQuery = new StationListQuery();
//                    listQuery.setLatitude(query.getLatitude());
//                    listQuery.setLongitude(query.getLongitude());
//                    listQuery.setPage_no(1);
//                    listQuery.setPage_size(size);
//
//                    String device_type = StringUtil.getTrim(component.get("device_type"));
//
//                    if(device_type != null && !device_type.equals("All")) {
//                        listQuery.setDeviceType(device_type);
//                    }
//
//                    Page<StationItemVO> page = this.getPage(listQuery);
//
//                    component.put("data_items", page.getResult());

                    break;
            }
        }

        pageData.put("items",componentList);
        return pageData;
    }
}
